package cz.muni.fi.pa165.languageschool;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 * Entity representing Course
 *
 * @author Michal Fučík (395624) michal.fuca.fucik(at)gmail.com
 */
@Entity
@Table(name = "Course")
@XmlRootElement
public class Course implements Comparable<Course>, Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(unique = true)
    private String code;

    @Column(unique = true)
    private String name;

    private Language taughtLanguage;

    private String requiredLevel;

    @OneToMany(mappedBy = "course", cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.LAZY)
    private List<Lecture> relatedLectures = new ArrayList<>();

    // -- Methods --------------------------------------------------------------
    /**
     * Id property getter
     *
     * @return
     */
    public Long getId() {
        return id;
    }

    /**
     * Id property setter
     *
     * @param id
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Name property getter
     *
     * @return
     */
    public String getName() {
        return name;
    }

    /**
     * Name property setter
     *
     * @param name
     */
    public void setName(String name) {
        if (name != null) {
            this.name = name;
        }
    }

    /**
     * Returns list of relatedLectures
     *
     * @return
     */
    @XmlTransient
    public List<Lecture> getRelatedLectures() {
        return relatedLectures;
    }

    /**
     * Sets up relatedLectures property
     *
     * @param lcs
     */
    public void setRelatedLectures(List<Lecture> lcs) {
        if (lcs != null) {
            this.relatedLectures = lcs;
        }
        for (Lecture l : lcs) {
            if (l.getCourse() != this) {
                l.setCourse(this);
            }
        }
    }

    /**
     * Adds given Lecture into Course's Lectures list and set up Lecture's
     * Course property to this Course
     *
     * @param lec
     */
    public void addLecture(Lecture lec) {
        if (lec != null) {
            this.relatedLectures.add(lec);
            if (lec.getCourse() != this) {
                lec.setCourse(this);
            }
        }
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    /**
     * Define language of the course
     *
     * @param courseLanguage taughtLanguage cannot be null
     */
    public void setCourseLanguage(Language courseLanguage) {
        this.taughtLanguage = courseLanguage;
    }

    /**
     * Get language of the course
     *
     * @return taughtLanguage
     */
    public Language getCourseLanguage() {
        return taughtLanguage;
    }

    /**
     * Define requiredLevel of the course.
     *
     * @param courseLevel requiredLevel cannot be null
     */
    public void setLevel(String courseLevel) {
        this.requiredLevel = courseLevel;
    }

    /**
     * Get requiredLevel of the course
     *
     * @return requiredLevel
     */
    public String getLevel() {
        return requiredLevel;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash += 13 * (this.id != null ? this.id.hashCode() : 0);
        hash += 13 * getCode().hashCode();
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Course other = (Course) obj;
        if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
            return false;
        }
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public int compareTo(Course c) {
        if (c == null) {
            throw new NullPointerException("Argument lec was null");
        }

        if (getId() == null) {
            if (getCode() != null) {
                return getCode().compareToIgnoreCase(c.getCode());
            }
        }
        return getId().compareTo(c.getId());
    }

    @Override
    public String toString() {
        return "[Course {id=" + getId() + ", code=" + getCode() + ", name=" + getName() + ", level=" + getLevel() + ", language=" + getCourseLanguage() + "}]";
    }
}
